Análise de dados - Salários¶

Importando as bibliotecas¶

In [167]:
import pandas as pd  # Importa a biblioteca pandas para manipulação de dados
import matplotlib.pyplot as plt  # Importa a biblioteca matplotlib para visualização de gráficos
import seaborn as sns  # Importa a biblioteca seaborn para gráficos mais sofisticados
import numpy as np 
import plotly.express as px
from sklearn.linear_model import LinearRegression

Importando arquivo¶

In [115]:
df = pd.read_csv("salaries.csv")

Tratamento de dados¶

In [116]:
#Verificar os primeiros registros
print(df.head().to_string())
   work_year experience_level employment_type                 job_title  salary salary_currency  salary_in_usd employee_residence  remote_ratio company_location company_size
0       2025               MI              FT  Customer Success Manager   57000             EUR          60000                 NL            50               NL            L
1       2025               SE              FT                  Engineer  165000             USD         165000                 US             0               US            M
2       2025               SE              FT                  Engineer  109000             USD         109000                 US             0               US            M
3       2025               SE              FT         Applied Scientist  294000             USD         294000                 US             0               US            M
4       2025               SE              FT         Applied Scientist  137600             USD         137600                 US             0               US            M
In [117]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 88584 entries, 0 to 88583
Data columns (total 11 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   work_year           88584 non-null  int64 
 1   experience_level    88584 non-null  object
 2   employment_type     88584 non-null  object
 3   job_title           88584 non-null  object
 4   salary              88584 non-null  int64 
 5   salary_currency     88584 non-null  object
 6   salary_in_usd       88584 non-null  int64 
 7   employee_residence  88584 non-null  object
 8   remote_ratio        88584 non-null  int64 
 9   company_location    88584 non-null  object
 10  company_size        88584 non-null  object
dtypes: int64(4), object(7)
memory usage: 7.4+ MB
In [118]:
#Verifica o tipo de dado
print('Tipagem:\n', df.dtypes)
Tipagem:
 work_year              int64
experience_level      object
employment_type       object
job_title             object
salary                 int64
salary_currency       object
salary_in_usd          int64
employee_residence    object
remote_ratio           int64
company_location      object
company_size          object
dtype: object
In [119]:
#Checar valores nulos
print('Valores nulos:\n', df.isnull().sum())
Valores nulos:
 work_year             0
experience_level      0
employment_type       0
job_title             0
salary                0
salary_currency       0
salary_in_usd         0
employee_residence    0
remote_ratio          0
company_location      0
company_size          0
dtype: int64
In [120]:
#Verifica a quantidade de registros
print('Qtd: ', df.shape)
Qtd:  (88584, 11)
In [121]:
#Padronizar textos
df['job_title'] = df['job_title'].str.lower().str.strip()
In [122]:
print('Estatísticas resumidas para colunas numéricas:')
display(df.describe())
Estatísticas resumidas para colunas numéricas:
work_year salary salary_in_usd remote_ratio
count 88584.000000 8.858400e+04 88584.000000 88584.000000
mean 2024.034758 1.619323e+05 157567.798417 21.286011
std 0.620370 1.965317e+05 73531.373158 40.831018
min 2020.000000 1.400000e+04 15000.000000 0.000000
25% 2024.000000 1.060000e+05 106097.250000 0.000000
50% 2024.000000 1.470000e+05 146307.000000 0.000000
75% 2024.000000 1.995000e+05 198600.000000 0.000000
max 2025.000000 3.040000e+07 800000.000000 100.000000
In [123]:
print('Estatísticas resumidas para colunas numéricas:')
display(df.describe(include=object))
Estatísticas resumidas para colunas numéricas:
experience_level employment_type job_title salary_currency employee_residence company_location company_size
count 88584 88584 88584 88584 88584 88584 88584
unique 4 4 312 26 96 90 3
top SE FT data scientist USD US US M
freq 51596 88111 13156 83994 79705 79762 85667
In [124]:
print(df.columns)
Index(['work_year', 'experience_level', 'employment_type', 'job_title',
       'salary', 'salary_currency', 'salary_in_usd', 'employee_residence',
       'remote_ratio', 'company_location', 'company_size'],
      dtype='object')

Processamento de dados¶

In [127]:
print(df["experience_level"].unique())
['Intermediate' 'Senior Expert' 'Junior' 'Executive Director']
In [126]:
experience_level = {
    "EN": "Junior",
    "MI": "Intermediate",
    "SE": "Senior Expert",
    "EX": "Executive Director"
}

df["experience_level"] = df["experience_level"].map(experience_level)
In [129]:
employment_type = {
    "PT": "Part-Time",
    "FT": "Full-Time",
    "CT": "Contract-Based",
    "FL": "Freelance"
}

df["employment_type"] = df["employment_type"].map(employment_type)
In [130]:
remote_work_ratio = {
    0: "On-Site",
    50: "Hybrid (50% Remote)",
    100: "Fully Remote"
}

df["remote_ratio"] = df["remote_ratio"].map(remote_work_ratio)
In [131]:
company_sizes = {
    "S": "Small Business",
    "M": "Mid-Sized Company",
    "L": "Large Enterprise"
}

df["company_size"] = df["company_size"].map(company_sizes)
In [132]:
salario_por_cargo = df.groupby('job_title')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_cargo.head(10)
Out[132]:
job_title
analytics engineering manager            399880.000000
data science tech lead                   375000.000000
applied ai ml lead                       292500.000000
head of machine learning                 283573.545455
machine learning performance engineer    262500.000000
head of ai                               261023.076923
engineering manager                      258633.717391
enterprise account executive             258258.535714
aws data architect                       258000.000000
director of machine learning             256479.545455
Name: salary_in_usd, dtype: float64

Média de salário por país¶

In [133]:
salario_por_pais = df.groupby('employee_residence')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_pais.head(10)
Out[133]:
employee_residence
QA    300000.000000
VE    192500.000000
CZ    189519.777778
US    163597.512854
IL    147321.733333
PR    146488.888889
SA    139999.333333
EG    132873.809524
AU    132236.050336
CA    131319.001873
Name: salary_in_usd, dtype: float64

Média de salário por nível de experiência¶

In [134]:
salario_por_experiencia = df.groupby('experience_level')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_experiencia.head(10)
Out[134]:
experience_level
Executive Director    200224.101130
Senior Expert         173033.652764
Intermediate          142708.823501
Junior                100316.106908
Name: salary_in_usd, dtype: float64

Média de salário por cargo¶

In [152]:
salario_por_cargo = df.groupby('job_title')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_cargo.head(10)
Out[152]:
job_title
analytics engineering manager            399880.000000
data science tech lead                   375000.000000
applied ai ml lead                       292500.000000
head of machine learning                 283573.545455
machine learning performance engineer    262500.000000
head of ai                               261023.076923
engineering manager                      258633.717391
enterprise account executive             258258.535714
aws data architect                       258000.000000
director of machine learning             256479.545455
Name: salary_in_usd, dtype: float64

Média de salário por modelo de trabalho (remoto=fully remote/híbrido=hybrid/presencial=on-site)¶

In [153]:
salario_por_modelo = df.groupby('remote_ratio')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_modelo.head(10)
Out[153]:
remote_ratio
On-Site                160196.306970
Fully Remote           148999.106211
Hybrid (50% Remote)     81255.192568
Name: salary_in_usd, dtype: float64

Média de salário em comparação com o tamanho da companhia¶

In [154]:
salario_por_tamanho = df.groupby('company_size')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_tamanho.head(10)
Out[154]:
company_size
Mid-Sized Company    157834.736526
Large Enterprise     154475.012209
Small Business        89773.471963
Name: salary_in_usd, dtype: float64

Média de salário por tipo de contrato (Meio período/Integral/Contrato/Freelance)ce"¶

In [157]:
salario_por_tipo = df.groupby('employment_type')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_tipo.head(10)
Out[157]:
employment_type
Full-Time         157959.297556
Contract-Based     96016.437500
Part-Time          76034.682403
Freelance          50651.562500
Name: salary_in_usd, dtype: float64

Média de salário por ano¶

In [158]:
salario_por_ano = df.groupby('work_year')['salary_in_usd'].mean().sort_values(ascending=False)
salario_por_ano.head(10)
Out[158]:
work_year
2024    159600.360607
2025    155174.567055
2023    153700.755456
2022    134175.359036
2020    102250.866667
2021     99922.073394
Name: salary_in_usd, dtype: float64

Visualização de dados¶

Top 10 países com a maior média salarial (USD)¶

In [169]:
# Contagem de registros por país
quantidade_por_pais = df['employee_residence'].value_counts().reset_index()
quantidade_por_pais.columns = ['País', 'Quantidade de Registros']

# Visualizar os 10 países com mais registros
quantidade_por_pais.head(10)
Out[169]:
País Quantidade de Registros
0 US 79705
1 CA 3203
2 GB 2576
3 AU 298
4 DE 263
5 FR 226
6 ES 203
7 LT 202
8 NL 187
9 AT 173
In [180]:
sns.barplot(
    data=quantidade_por_pais.head(10),
    x='Quantidade de Registros',
    y='País',
    hue='País',
    palette='crest',
    dodge=False
)

plt.legend([],[], frameon=False)  # isso oculta a legenda sem dar erro
plt.title('Top 10 Países com Maior Número de Registros no Dataset', fontsize=14, fontweight='bold')
plt.xlabel('Número de Registros')
plt.ylabel('País')
plt.grid(True, axis='x', linestyle='--', alpha=0.5)
plt.show()
No description has been provided for this image
In [178]:
plt.figure(figsize=(12, 6))
sns.barplot(
    x=salario_por_pais.head(10).values,
    y=salario_por_pais.head(10).index,
    hue=salario_por_pais.head(10).index,  # define o hue igual ao y
    palette='viridis',
    legend=False                          # remove legenda já que y é hue
)

plt.title('Top 10 Países com Maior Média Salarial (USD)', fontsize=14, fontweight='bold')
plt.xlabel('Salário Médio (USD)', fontsize=12)
plt.ylabel('País de Residência do Funcionário', fontsize=12)
plt.grid(axis='x', linestyle='--', alpha=0.4)
plt.tight_layout()
plt.show()
No description has been provided for this image
In [181]:
# Os EUA dominam o conjunto de dados - Sozinho, os Estados Unidos representam mais de 90% do total de registros, nesse caso
# é visível que o dataframe é enviesado para o mercado americano. Em seguida, acompanha o Canadá e o Reino Unido, ainda que distante
# da média salarial dos EUA. E ainda, há pouca representatividade dos outros países (Alemanha, França, Espanha, Lituânia, etc.) por possuirem menos de 
# 300 registros.

Relação da média salarial pelo nível de experiência, adicionando o cargo¶

In [144]:
fig = px.scatter(
    df,
    x="experience_level",
    y="salary_in_usd",
    size="salary_in_usd",
    color="experience_level",
    hover_name="job_title",   # o que aparece ao passar o mouse
    title="Salário vs. Nível de Experiência (com cargo no hover)",
    labels={"salary_in_usd": "Salário (USD)", "experience_level": "Nível de Experiência"},
    height=600
)

fig.update_traces(marker=dict(opacity=0.5, line=dict(width=1, color='DarkSlateGrey')))
fig.show()
In [ ]:
# Intermediate e Senior Expert representa as maiores concentrações dos pontos, representação a maioria dos profissionais. A variação 
# salarial é significativa nesses grupos (baixos e altos salários).
# Junior tem mais pontos concentrados em salários mais baixos, porém alguns destoam com salários bem altos (podendo existir alguma exceção, cargos raros
# ou erros de registros.
# Executive Director tem menos registros, mas uma faixa salarial muito alta e consistente. Pouca dispersão indica padrões salariais mais alinhados, 
# o que é comum em altos cargos executivos.

Gráfico de médias saláriais por cargo, de acordo com o tipo de contrato¶

In [147]:
# Agrupa por cargo e tipo de contrato, tirando a média
media_salario = df.groupby(['job_title', 'employment_type'])['salary_in_usd'].mean().reset_index()

# (Opcional) limitar aos cargos mais frequentes pra não poluir
top_cargos = df['job_title'].value_counts().nlargest(10).index
media_salario = media_salario[media_salario['job_title'].isin(top_cargos)]

# Gráfico interativo
fig = px.bar(
    media_salario,
    x='job_title',
    y='salary_in_usd',
    color='employment_type',
    barmode='group',  # barras agrupadas por tipo de contrato
    title='Média Salarial por Cargo e Tipo de Contrato',
    labels={
        'job_title': 'Cargo',
        'salary_in_usd': 'Salário Médio (USD)',
        'employment_type': 'Tipo de Contrato'
    },
    height=600
)

fig.update_layout(xaxis_tickangle=-45)
fig.show()
In [ ]:
#Full-Time (vermelho) domina com os maiores salários médios em praticamente todos os cargos.
#Destaque para: Machine Learning Engineer, Research Scientist, Software Engineer
#Nesses cargos, os salários ultrapassam facilmente os $190k.

#Contract-Based (azul):
#É competitivo em algumas áreas como:
#Software Engineer (próximo ou até acima do full-time)
#Data Engineer e Research Scientist
#Indica que contratos por projeto em tech avançada podem pagar muito bem.

#Freelance (roxo):
#Aparece com valores medianos, mas interessante em:
#Machine Learning Engineer (quase $100k)
#Engineer e Software Engineer

#Part-Time (verde):
#Em geral, representa os menores salários, como esperado.
#Um ponto curioso: Software Engineer part-time chega a ultrapassar $150k — isso pode ser por carga horária reduzida em empresas de alto valor agregado.

Gráfico de pizzas - Média salarial por modelo de trabalho (remoto=fully remote/híbrido=hybrid/presencial=on-site)¶

In [150]:
fig = px.pie(
    df,
    names='remote_ratio',        # o que vai nas fatias
    values='salary_in_usd',         # peso de cada fatia (pode ser contagem também)
    title='Distribuição de Salários por Modelo de Trabalho',
    hole=0.3                         # se quiser tipo "donut", senão tira isso
)
fig.show()
In [ ]:
#1. On-Site (Presencial) – 79,9%
#A maior parte dos salários está concentrada em empregos presenciais.
#Isso pode indicar:
#Maior número de posições presenciais no dataset.
#Ou que as empresas pagam mais no modelo presencial, talvez por funções mais tradicionais ou de liderança que exigem presença física.

#2. Fully Remote (100% Remoto) – 20%
#Apesar de todo o crescimento do trabalho remoto nos últimos anos, a fatia de distribuição de salários ainda é significativamente menor.
#Pode sugerir:
#Menor número de vagas 100% remotas bem remuneradas.
#Ou que empresas ainda oferecem salários menores nesse modelo (em alguns casos, compensado por benefícios como flexibilidade).

#3. Hybrid (50% Remoto) – 0,17%
#Praticamente inexistente no gráfico.
#Isso pode indicar duas coisas:
#O dataset tem pouquíssimos registros híbridos.

#Ou essas posições pagam valores muito baixos comparativamente.

Gráfico média de salários em relação ao tamanho da companhia¶

In [159]:
salario_por_tamanho_df = salario_por_tamanho.reset_index()

# Gráfico de barras
fig = px.bar(
    salario_por_tamanho_df,
    x='company_size',
    y='salary_in_usd',
    title='Média Salarial por Tamanho da Empresa',
    labels={'company_size': 'Tamanho da Empresa', 'salary_in_usd': 'Salário Médio (USD)'},
    color='company_size',
    text_auto='.2s'
)

fig.update_layout(showlegend=False)
fig.show()
In [ ]:
#1. Mid-Sized Company (Empresa de Médio Porte) – 160k USD
#Maior média salarial entre os três portes.
#Pode indicar que empresas de médio porte:
#Estão em fase de crescimento acelerado e precisam atrair talentos com salários competitivos.
#São mais flexíveis em negociação de salário do que grandes corporações.

#2. Large Enterprise (Grande Empresa) – 150k USD
#Apesar de terem mais recursos, ficam atrás das médias empresas.
#Explicações possíveis:
#Mais estrutura e faixas salariais padronizadas.
#Benefícios indiretos compensam parte do salário direto.
#Grande número de cargos de entrada pode puxar a média para baixo.

#3. Small Business (Pequena Empresa) – 90k USD
#Menor média salarial.
#Natural, já que pequenas empresas:
#Têm menos capital disponível.
#Podem oferecer salários menores, mas compensar com flexibilidade, cultura ou participação societária (em alguns casos).

Média salarial por tipo de contrato e Nível de Experiência

In [162]:
# Cria DataFrame com médias por tipo de contrato + nível de experiência
media_contrato_experiencia = df.groupby(['employment_type', 'experience_level'])['salary_in_usd'].mean().reset_index()

# Gráfico de barras agrupadas
plt.figure(figsize=(12, 6))
sns.barplot(
    data=media_contrato_experiencia,
    x='employment_type',
    y='salary_in_usd',
    hue='experience_level',
    palette='Set2'
)

plt.title('Média Salarial por Tipo de Contrato e Nível de Experiência', fontsize=14, fontweight='bold')
plt.xlabel('Tipo de Contrato')
plt.ylabel('Salário Médio (USD)')
plt.legend(title='Nível de Experiência')
plt.tight_layout()
plt.show()
No description has been provided for this image
In [ ]:
#Contract-Based
#Executive Director lidera, com média salarial acima de 190k USD.
#Senior Expert também se destaca, perto de 120k USD.
#Esse tipo de contrato pode envolver consultorias de alto nível ou projetos temporários bem remunerados.

#Freelance
#Média salarial mais baixa, especialmente para níveis mais altos.
#Pode indicar que:
#Muitos freelancers ainda estão em início de carreira ou atuam em projetos curtos.
#Ou que há grande variabilidade nos ganhos (nem todos ganham valores altos com consistência).
#Junior e Senior Expert ficam entre 55k–65k USD.

#Part-Time
#Faixas mais compactas e médias salariais mais baixas que as outras categorias.
#Mesmo um Senior Expert ganha menos de 130k USD.
#Pode indicar que cargos de meio período oferecem menos retorno financeiro direto, ainda que tenham mais flexibilidade.

#Full-Time
#Apresenta os valores mais altos em todas as categorias, especialmente:
#Executive Director: ultrapassa os 200k USD.
#Senior Expert: por volta de 175k USD.
#Evidencia que a carreira tradicional (full-time) continua sendo a que oferece maior retorno financeiro, principalmente com mais experiência.

Gráfico - Média salarial ao longo dos anos (cargo)¶

In [165]:
plt.figure(figsize=(14, 7))
sns.lineplot(
    data=df_filtrado,
    x='work_year',
    y='salary_in_usd',
    hue='job_title',
    estimator='mean',
    errorbar=None,     # <- substitui ci=None
    marker='o'
)

plt.title('Evolução da Média Salarial por Cargo ao Longo dos Anos', fontsize=14, fontweight='bold')
plt.xlabel('Ano')
plt.ylabel('Salário Médio (USD)')
plt.legend(title='Cargo')
plt.grid(True, linestyle='--', alpha=0.5)
plt.tight_layout()
plt.show()
No description has been provided for this image
In [ ]:
#Destaques e Tendências por Cargo
#Machine Learning Engineer
#Em 2020, tinha o maior salário (acima de 240k USD!), mas despencou em 2021.
#Depois disso, recuperou bem e se estabilizou entre 190k–200k USD até 2025.
#Indica uma possível bolha ou pico de valorização em 2020, seguida de ajuste.

#Data Scientist & Software Engineer
#Seguem trajetórias similares: queda leve em 2021, forte alta em 2022, e estabilidade nos últimos anos.
#Em 2025, ambos estão acima de 180k USD, o que mostra alta valorização do conhecimento técnico aplicado.

#Manager
#Crescimento bem marcado entre 2021 e 2023.
#Se mantém no topo dos salários em 2024 e 2025, chegando aos 200k USD.
#Confirma que cargos de liderança técnica continuam muito valorizados.

#Data Engineer
#Crescimento constante desde 2021.
#Em 2025, se aproxima de 150k USD, o que mostra que a área está em ascensão e valorizada.

#Research Scientist
#Cresce até 2023, mas começa a cair em 2024–2025, ficando abaixo de 150k USD.
#Pode indicar menor demanda em setores mais acadêmicos ou de pesquisa pura.

#Engineer (genérico) e Data Analyst
#Têm os salários mais baixos da lista.
#Data Analyst fica abaixo de 100k USD em todos os anos, com leve declínio em 2025.
#Isso reforça a ideia de que quanto mais especializada a função, maior a remuneração.